package dyyx.bloomfilter;

import java.util.Arrays;

import javax.annotation.Nullable;

// Note: We use this instead of java.util.BitSet because we need access to the long[] data field
public class MyBitArray {
	final long[] data;
	long bitCount;

	public MyBitArray(long bits) {
		this(new long[(int) (bits / 64)]);
	}

	// Used by serialization
	public MyBitArray(long[] data) {
		// checkArgument(data.length > 0, "data length is zero!");
		this.data = data;
		long bitCount = 0;
		for (long value : data) {
			bitCount += Long.bitCount(value);
		}
		this.bitCount = bitCount;
	}

	/** Returns true if the bit changed value. */
	public boolean set(long index) {
		if (!get(index)) {
			data[(int) (index >>> 6)] |= (1L << index);
			bitCount++;
			return true;
		}
		return false;
	}

	public boolean get(long index) {
		return (data[(int) (index >>> 6)] & (1L << index)) != 0;
	}

	/** Number of bits */
	public long bitSize() {
		return (long) data.length * Long.SIZE;
	}

	/** Number of set bits (1s) */
	public long bitCount() {
		return bitCount;
	}

	public MyBitArray copy() {
		return new MyBitArray(data.clone());
	}

	/** Combines the two BitArrays using bitwise OR. */
	public void putAll(MyBitArray array) {

		bitCount = 0;
		for (int i = 0; i < data.length; i++) {
			data[i] |= array.data[i];
			bitCount += Long.bitCount(data[i]);
		}
	}

	@Override
	public boolean equals(@Nullable Object o) {
		if (o instanceof MyBitArray) {
			MyBitArray bitArray = (MyBitArray) o;
			return Arrays.equals(data, bitArray.data);
		}
		return false;
	}

	@Override
	public int hashCode() {
		return Arrays.hashCode(data);
	}
}